package someTestExcemple.reflect;

import DTO.Address;
import DTO.Student;
import someTestExcemple.reflect.annotation.AnnotationTest1;
import someTestExcemple.reflect.annotation.MyAnnotation1;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class reflectTest1 {
    public static void main(String[] args) throws Exception {
        //testClass();
        //testConstructor();
        //testFiled();
        //testMethod();
        testAnnotation();
    }
    //反射获取class对象
    public static void testClass() throws ClassNotFoundException {
        //反射学习 获取class对象
        //1. 获取class对象
        Class c1 = Student.class;
        System.out.println("c1.getName: "+ c1.getName()); //获取全类名：DTO.Student 包名.类名
        System.out.println("c1.getSimpleName: "+ c1.getSimpleName());
        //2.Class.forName()获取class对象 括号里面是类的全类名(类路径)
        Class c2 = Class.forName("DTO.Student");
        System.out.println("c2.getName: " + c2.getName());
        System.out.println(c1.getName() == c2.getName()); //true 内存中的class对象是同一个
        //3.Object提供的方法：对象实例.getClass()获取class对象
        Student student = new Student("张三", 1);
        Class c3 = student.getClass();
        System.out.println("c3.getName: " + c3.getName());
        System.out.println(c1.getName() == c3.getName());
    }


    //反射获取类构造器
    public static void testConstructor() throws Exception
    {
        Class c = Student.class;
        //获取类的全部公开构造器 ---getConstructors()只能获取public修饰的构造器
        //Constructor[] constructors = c.getConstructors();
        Constructor[] constructors = c.getDeclaredConstructors(); //获取全部构造器 --推荐用这个
        //遍历数组中的每个构造器
        for (Constructor constructor : constructors) {
            System.out.println("构造器名称：" + constructor.getName());
            System.out.println("构造器参数个数: " + constructor.getParameterCount());
            //获取构造器的参数类型
            Class[] parameterTypes = constructor.getParameterTypes();
            //遍历参数类型数组
            for (Class parameterType : parameterTypes) {
                System.out.println(parameterType);
            }
        }

        System.out.println("------------------------------------");
        Class c1 = Address.class;
        //获取指定参数类型的构造器 -- 还是推荐用DeclaredConstructor()
        Constructor constructor = c.getDeclaredConstructor(String.class, Integer.class, Address.class);
        Constructor constructor1 = c1.getDeclaredConstructor(String.class, String.class, String.class);
        System.out.println("constructor==>" + constructor);
        //通过获取类的构造器-来初始化对象返回
        Address address = (Address) constructor1.newInstance("中国", "江苏", "南京");
        constructor.setAccessible(true); //设置为true 表示禁止访问检查控制 - 构造器为私有的也可以访问
        Student student = (Student) constructor.newInstance("张三", 1,address);
        System.out.println(student);

    }

    //反射获取成员变量
    public static void testFiled() throws Exception {
        Class c = Address.class;
        Field[] fields= c.getDeclaredFields();
        //遍历所用成员变量
        for (Field declaredField : fields) {
            //获取成员变量的名称和类型
            System.out.println("filedName==>" + declaredField.getName() + " filedType==>" + declaredField.getType());
        }
        //定位某个成员变量
         Field field = c.getDeclaredField("cityName");
        System.out.println("field==>" + field);
        //对成员变量进行赋值和取值
        Address address = new Address("中国", "江苏", "南京");
        field.setAccessible(true);
        field.set(address,"镇江");
        System.out.println(address);
        //获取成员变量的值
        String newCityName = (String) field.get(address);
        System.out.println(newCityName);
    }
    //反射获取成员方法
    public static void testMethod() throws Exception {
        Class c = Address.class;

         Method[] methods = c.getDeclaredMethods();
         for (Method method : methods) {
             System.out.println("methodName: " + method.getName() + " methodType:" + method.getReturnType());
             //获取参数个数
             System.out.println("methodParameterCount: " + method.getParameterCount());
             //获取参数类型
             Class[] parameterTypes = method.getParameterTypes();
             for (Class parameterType : parameterTypes) {
                 System.out.println("parameterType: " + parameterType);
                 System.out.println("parameterName>" + parameterType.getName());
             }
         }
         //获取指定参数类型的方法
       //Method m = c.getMethod("checkAddress", int.class, int.class); //会报错，因为访问不到私有的方法
        Method m = c.getDeclaredMethod("checkAddress", int.class, int.class);
        System.out.println("m==>" + m);
        //执行成员方法
        Address address = new Address("中国", "江苏", "南京");
        //如果方法是私有的，要invoke执行的话,需要设置setAccessible(true)
        m.setAccessible(true);
        //invoke()方法执行成员方法
       boolean result = (boolean) m.invoke(address, 4, 1);
        System.out.println(result);


    }
    //解析注解
    public static void testAnnotation() throws Exception {
        Class c = AnnotationTest1.class;
         Annotation[] annotations = c.getDeclaredAnnotations();
        System.out.println("annotations==>");
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        Class c1 = Student.class;
        Annotation[] annotations1 = c1.getDeclaredAnnotations();
        System.out.println("Student,annotations==>");
        for (Annotation annotation : annotations1) {
            System.out.println(annotation);
//            if(annotation instanceof MyAnnotation1) {
//
//            }
        }
        System.out.println("Student have MyAnnotation1:");
        //判断该类上是否存在MyAnnotation1注解
        if(c1.isAnnotationPresent(MyAnnotation1.class)) {
            MyAnnotation1 annotation = (MyAnnotation1) c1.getAnnotation(MyAnnotation1.class);
            System.out.println(annotation);
            //返回注解的类 --> MyAnnotation1的全类名
            System.out.println(annotation.annotationType());
            System.out.println(annotation.age());
            System.out.println(annotation.name());
            System.out.println(annotation.sex());
        }

    }

}
